/*
 * main.cpp
 *
 *  Created on: 30.09.2012
 *      Author: dom
 */

#include <string>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <memory>
#include <algorithm>
#include <locale>
#include <iosfwd>
#include <regex>

#include "token.hpp"
#include "document.hpp"
#include "document_class.hpp"
#include "algorithm.hpp"
#include "data_reader.hpp"

#include "stem/russian_stem.h"
#include "stem/english_stem.h"

using namespace mpei;
using namespace std;

typedef Document<token_t> document_t;
typedef DocumentClass<document_t> document_class_t;

const double kPercent = 0.1;
const uint16_t kNumNeighbors = 20;
const uint16_t kClasses_begin = 5;
const uint16_t kClasses = 6;

int main(int argc, char **argv) {
	std::cout << "Classes: " << kClasses << std::endl;
//	std::cout << " kPercent: " << kPercent << std::endl;

	auto data_reader = DataReader<>::shared_ptr(
			new data_reader_t(
					"https://classification-mizinov.rhcloud.com/api/"));
	DataReader<>::container doc_classes;
	data_reader->getClasses(doc_classes);
	std::vector<document_class_t::shared_ptr> collection;
	std::vector<document_class_t::shared_ptr> other_collection;
	uint8_t i = 0;
	for (auto class_name : doc_classes) {
//		if (i > 0 && i < 6) { // russian
		if (i > kClasses_begin && i < kClasses_begin + kClasses + 1) { // english
//				std::cout << class_name << std::endl;
			collection.push_back(
					document_class_t::shared_ptr(
							new document_class_t(class_name)));
			other_collection.push_back(
					document_class_t::shared_ptr(
							new document_class_t(class_name)));
			data_reader->getDocuments(kPercent, class_name, collection.back(),
					other_collection.back());
		}
		++i;
	}

	auto all_documents_ = document_class_t::container();
	std::vector<document_t::shared_ptr> centroids_;
	for (auto doc_class : collection) {
		for (auto doc : doc_class->get()) {
			doc->calculate();
		}
		all_documents_.insert(doc_class->get().begin(), doc_class->get().end());
		centroids_.push_back(doc_class->getCentroid());
	}
	Algorithm::kMNN_train(all_documents_.begin(), all_documents_.end(),
			centroids_);
//	ClassCount<document_class_t, double> centroid_count_;
//	ClassCount<document_class_t, double> knn_count_;
//	ClassCount<document_class_t, double> kmnn_count_;
//	ClassCount<document_class_t, double> nb_count_;

	auto centroid_count_ = ClassCount<document_class_t, double>();
	auto nb_count_ = ClassCount<document_class_t, double>();
	for (auto other_class : other_collection) {
		for (auto other_doc : other_class->get()) {
			other_doc->calculate();
			//Centroid
			auto classif_class_centroid = Algorithm::centroid<document_class_t>(
					collection.begin(), collection.end(), other_doc);
			centroid_count_(classif_class_centroid,
					other_doc->getDocumentClass());
//			//NaiveBayes
//			auto classif_class_nb = Algorithm::naive_bayes<document_class_t>(
//					collection.begin(), collection.end(), other_doc,
//					all_documents_.size());
//			nb_count_(classif_class_nb, other_doc->getDocumentClass());

		}
	}
	std::cout << "Centroid error " << centroid_count_.error() << std::endl;
	std::cout << "Naive Bayes error " << nb_count_.error() << std::endl;

	for (uint8_t NN = 1; NN < kNumNeighbors; ++NN) {
		auto knn_count_ = ClassCount<document_class_t, double>();
		auto kmnn_count_ = ClassCount<document_class_t, double>();
		for (auto other_class : other_collection) {
		std::cout << other_class->getClassName() << std::endl;
			for (auto other_doc : other_class->get()) {

//				//kNN
//				auto classif_class_knn = Algorithm::kNN<document_class_t>(
//						all_documents_.begin(), all_documents_.end(), other_doc,
//						NN);
//				knn_count_(classif_class_knn, other_doc->getDocumentClass());

				//kMNN
				auto classif_class_kmnn = Algorithm::kMNN<document_class_t>(
						all_documents_.begin(), all_documents_.end(), other_doc,
						centroids_, NN);
				kmnn_count_(classif_class_kmnn, other_doc->getDocumentClass());

			}
		}
		std::cout << "Knn error " << knn_count_.error() << " NN: "
				<< (uint32_t) NN << std::endl;
		std::cout << "KMnn error " << kmnn_count_.error() << " NN: "
				<< (uint32_t) NN << std::endl;
	}

//	auto doc_ = document_t::shared_ptr(new document_t("document1"));
//	auto doc_6 = document_t::shared_ptr(new document_t("document6"));
//	auto doc_class_ = new DocumentClass<Document<token_t>>("class1");
//	doc_class_->insert(doc_);
//	doc_class_->insert(doc_6);
//	auto token1 = token_t::shared_ptr(new token_t("token1"));
//	auto token2 = token_t::shared_ptr(new token_t("token2"));
//	auto token3 = token_t::shared_ptr(new token_t("token3"));
//	auto token4 = new token_t("token4");
//	try {
//		doc_->insert(token1);
//		doc_->insert(token2);
//		doc_->insert(token3);
//		doc_->insert(token4);
//		doc_6->insert(token1);
//		doc_6->insert(token4);
//	} catch (std::exception & e) {
//		std::cout << e.what();
//		throw;
//	}
//
//	//other documents
//	auto other_class_ = new DocumentClass<Document<token_t>>("other");
//	auto doc_2 = document_t::shared_ptr(new document_t("document2"));
//	other_class_->insert(doc_2);
//	doc_2->insert(token2);
//	auto token5 = token_t::shared_ptr(new token_t("token5"));
//	doc_2->insert(token5);
//	++(token5);
//	auto doc_3 = document_t::shared_ptr(new document_t("document3"));
//	other_class_->insert(doc_3);
//	doc_3->insert(token1);
//	auto token6 = token_t::shared_ptr(new token_t("token6"));
//	doc_3->insert(token6);
//	++(token6);
//	++(token6);
//	auto doc_class_2 = new DocumentClass<Document<token_t>>("class2");
//	doc_class_2->insert(doc_);
//	doc_class_2->insert(doc_6);
//
//	auto all_documents_ = DocumentClass<Document<token_t>>::container();
//	all_documents_.insert(doc_class_2->get().begin(), doc_class_2->get().end());
//	all_documents_.insert(doc_class_2->get().begin(), doc_class_2->get().end());
//
////	std::move(documents_.begin(),documents_.end(),all_documents_.begin());
////	std::copy(documents_2.begin(),documents_2.end(),all_documents_.end());
//	auto other_documents_ = other_class_->get();
//	uint8_t NumNeghbors_ = 2;
//	for (auto other_ : other_documents_) {
//		std::cout << "Other document: " << other_->getDocumentName()
//				<< std::endl;
//		std::map<document_t::shared_ptr, double> neareNeigbors;
//		kNN(all_documents_.begin(), all_documents_.end(), other_, NumNeghbors_,
//				neareNeigbors);
//		for (auto doc_ : neareNeigbors) {
//			std::cout << doc_.first->getDocumentName() << doc_.second;
//		}
//	}
//
//	std::string str = std::string("ЁлОчка");
//	auto converter = ConverterUtf8();
//	std::wstring wstr1 = converter(str);
//	stemming::russian_stem<std::wstring> stemRus;
////	stemming::english_stem<std::wstring> stemEng;
//	stemRus(wstr1);
//	std::string str2 = converter(wstr1);
//	std::cout << str2 << std::endl;
//	std::vector<std::string> strs;
//	std::vector<std::string>::iterator it1;
//	for (it1 = strs.begin(); it1 != strs.end(); ++it1) {
//
//	}
	return 0;
}
